/*
	@file: log/source/FileLogger.cpp
	@author: Wolfhead
 */
#include "logger/FileLogger.h"
#include <boost/date_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include "Log.h"

namespace fs = boost::filesystem;

namespace logger
{

FileLogger::FileLogger(const std::string& path)
	: m_path(path)
	, m_interval(0)
{

}

int FileLogger::set_interval(const std::string& interval)
{
	boost::lock_guard<boost::mutex> lock(m_mutex);

	if (0 != parse_interval(interval, m_interval))
	{
		return -1;
	}

	if (0 != refresh_file(true))
	{
		return -1;
	}

	return 0;
}

int FileLogger::set_interval(time_t interval)
{
	boost::lock_guard<boost::mutex> lock(m_mutex);

	m_interval = interval;

	if (0 != refresh_file(true))
	{
		return -1;
	}

	return 0;
}

int FileLogger::log(const std::string& message)
{
	boost::lock_guard<boost::mutex> lock(m_mutex);

	if (0 != refresh_file())
	{
		return -1;
	}

	if (!m_file)
	{
		return -1;
	}

	fputs(message.c_str(), m_file.get());
	fputs("\n", m_file.get());

	return 0;
}

int FileLogger::log(const std::vector<std::string>& message_vec)
{
	boost::lock_guard<boost::mutex> lock(m_mutex);

	if (0 != refresh_file())
	{
		return -1;
	}

	if (!m_file)
	{
		return -1;
	}

	BOOST_FOREACH(const std::string& message, message_vec)
	{
		fputs(message.c_str(), m_file.get());
		fputs("\n", m_file.get());
	}

	return 0;
}

int FileLogger::flush()
{
    if (m_file)
    {
        fflush(m_file.get());
    }

    return 0;
}

int FileLogger::refresh_file(bool force_refresh /*= false */)
{
	if (force_refresh)
	{
		m_file = boost::shared_ptr<FILE>();
	}

	if (m_interval)
	{
		time_t now = time(NULL);

		if (now - m_file_time >= m_interval || !m_file)
		{
			if (0 != open_file())
			{
				CLOGF(kError, "FileLogger::refresh_file fail");
				return -1;
			}
		}

		return 0;
	}
	else
	{
		if (!m_file)
		{
			if (0 != open_file())
			{
				CLOGF(kError, "FileLogger::refresh_file fail");
				return -1;
			}

			m_file_time = 0;
		}
		return 0;
	}
}

int FileLogger::open_file()
{
	static const size_t buffer_size = 512;

	// get file time
	time_t now = time(NULL);
	struct timezone tz;
	struct timeval tv;
	gettimeofday(&tv, &tz);	
	struct tm tm;
	time_t algin_time = 
        m_interval == 0 ?
        now :
		now - ((now - tz.tz_minuteswest * 60) % m_interval);

	localtime_r(&algin_time, &tm);
	
	// get file path
	char buffer[buffer_size];
	int ret = strftime(buffer, buffer_size - 1, m_path.c_str(), &tm);

	if (ret < 0)
	{
		CLOGF(kError, "FileLogger::open_file strftime %s fail"
			, m_path.c_str());
		return -1;
	}

    fs::path path(buffer);
    path = fs::system_complete(path);

    fs::path parent_dir = path;
    parent_dir.remove_filename();

    // nothig we can do if create dir fail
    fs::create_directories(parent_dir);

    FILE * file_ptr = fopen(path.string().c_str(), "a+");
    if (NULL == file_ptr)
    {
    	CLOGF(kError, "FileLogger::open_file %s fail"
    		, path.string().c_str());
    	return -1;
    }

    m_file = boost::shared_ptr<FILE>(file_ptr, fclose);
    m_file_time = algin_time;

    CLOGF(kDebug, "FileLogger::open_file %s success"
    	, path.string().c_str());

    return 0;
}


int FileLogger::parse_interval(const std::string& interval, long& seconds)
{
	boost::posix_time::time_duration td(
		boost::posix_time::duration_from_string(interval));

	if (td.is_not_a_date_time())
	{
		CLOGF(kError, "FileLogger::parse_interval %s fail"
			, interval.c_str());
		return -1;
	}

	seconds = td.total_seconds();

	return 0;
}

}//namespace logger

